-- ============================================================================
-- 网络摄像头 Lua 插件示例
-- 协议：IPCamera-Private（私有协议示例，非标准ONVIF）
-- 功能：设备注册、心跳、报警推送、云台控制
-- ============================================================================

protocol_name = "IPCamera-Private"

-- ============================================================================
-- 辅助函数
-- ============================================================================

-- CRC16 校验计算
local function calcCRC16(data, start_pos, end_pos)
    local crc = 0xFFFF
    for i = start_pos, end_pos do
        crc = crc ~ data[i]
        for j = 0, 7 do
            if (crc & 0x0001) ~= 0 then
                crc = (crc >> 1) ~ 0xA001
            else
                crc = crc >> 1
            end
        end
    end
    return crc
end

-- 验证数据包
local function validatePacket(data, dataLen)
    if dataLen < 10 then
        return false, "数据长度不足"
    end
    
    -- 帧头检查：0xFF 0xFE
    if data[1] ~= 0xFF or data[2] ~= 0xFE then
        return false, "帧头错误"
    end
    
    -- 长度检查
    local length = data[3] * 256 + data[4]
    if length ~= dataLen then
        return false, string.format("长度不匹配: 声明%d, 实际%d", length, dataLen)
    end
    
    -- CRC16 校验
    local crc_recv = data[dataLen-1] * 256 + data[dataLen]
    local crc_calc = calcCRC16(data, 1, dataLen - 2)
    if crc_recv ~= crc_calc then
        return false, string.format("CRC校验失败: 期望%04X, 实际%04X", crc_calc, crc_recv)
    end
    
    return true, "OK"
end

-- 解析设备序列号（MAC地址格式）
local function extractDeviceSerial(data)
    if #data >= 11 then
        return string.format("%02X:%02X:%02X:%02X:%02X:%02X",
            data[5], data[6], data[7], data[8], data[9], data[10])
    end
    return ""
end

-- 云台方向转换
local function getPTZDirection(direction_code)
    local directions = {
        [0x01] = "上",
        [0x02] = "下",
        [0x03] = "左",
        [0x04] = "右",
        [0x05] = "左上",
        [0x06] = "左下",
        [0x07] = "右上",
        [0x08] = "右下",
        [0x09] = "放大",
        [0x0A] = "缩小",
        [0x00] = "停止"
    }
    return directions[direction_code] or "未知"
end

-- ============================================================================
-- 核心函数：数据解析
-- ============================================================================

function AnalysisRx(deviceAddr, variables, data, dataLen)
    -- 验证数据包
    local valid, msg = validatePacket(data, dataLen)
    if not valid then
        print(string.format("[IPCamera] 数据包验证失败: %s", msg))
        return false
    end
    
    -- 获取命令码
    local cmd = data[11]
    
    if cmd == 0x01 then
        -- 设备注册
        local serial = extractDeviceSerial(data)
        local model = string.format("%c%c%c%c%c%c%c%c",
            data[12], data[13], data[14], data[15],
            data[16], data[17], data[18], data[19])
        local firmware = string.format("%d.%d.%d", data[20], data[21], data[22])
        local channel_count = data[23]
        
        table.insert(variables, {
            Name = "frame_type",
            Description = "帧类型",
            Value = "login"
        })
        
        table.insert(variables, {
            Name = "device_serial",
            Description = "设备序列号",
            Value = serial
        })
        
        table.insert(variables, {
            Name = "device_model",
            Description = "设备型号",
            Value = model
        })
        
        table.insert(variables, {
            Name = "firmware_version",
            Description = "固件版本",
            Value = firmware
        })
        
        table.insert(variables, {
            Name = "channel_count",
            Description = "通道数",
            Value = channel_count
        })
        
        print(string.format("[IPCamera] 设备注册: 序列号=%s, 型号=%s, 版本=%s, 通道=%d",
            serial, model, firmware, channel_count))
        
        return true
        
    elseif cmd == 0x02 then
        -- 心跳包
        local status = data[12]
        local cpu_usage = data[13]
        local memory_usage = data[14]
        local temperature = data[15]
        local storage_status = data[16]
        
        table.insert(variables, {
            Name = "frame_type",
            Description = "帧类型",
            Value = "heartbeat"
        })
        
        table.insert(variables, {
            Name = "device_status",
            Description = "设备状态",
            Value = status == 0x00 and "正常" or "异常"
        })
        
        table.insert(variables, {
            Name = "cpu_usage",
            Description = "CPU使用率",
            Value = cpu_usage,
            Unit = "%"
        })
        
        table.insert(variables, {
            Name = "memory_usage",
            Description = "内存使用率",
            Value = memory_usage,
            Unit = "%"
        })
        
        table.insert(variables, {
            Name = "temperature",
            Description = "温度",
            Value = temperature,
            Unit = "℃"
        })
        
        table.insert(variables, {
            Name = "storage_status",
            Description = "存储状态",
            Value = storage_status == 0x00 and "正常" or (storage_status == 0x01 and "告警" or "故障")
        })
        
        print(string.format("[IPCamera] 设备%s 心跳: 状态=%s, CPU=%d%%, 内存=%d%%, 温度=%d℃",
            deviceAddr, status == 0x00 and "正常" or "异常", cpu_usage, memory_usage, temperature))
        
        return true
        
    elseif cmd == 0x03 then
        -- 报警推送
        local alarm_type = data[12]
        local channel = data[13]
        local alarm_time = data[14] * 16777216 + data[15] * 65536 + data[16] * 256 + data[17]  -- Unix时间戳
        local has_snapshot = data[18]
        
        local alarm_desc = ""
        if alarm_type == 0x01 then
            alarm_desc = "移动侦测"
        elseif alarm_type == 0x02 then
            alarm_desc = "遮挡报警"
        elseif alarm_type == 0x03 then
            alarm_desc = "音频异常"
        elseif alarm_type == 0x04 then
            alarm_desc = "存储异常"
        elseif alarm_type == 0x05 then
            alarm_desc = "网络断开"
        elseif alarm_type == 0x06 then
            alarm_desc = "人形检测"
        elseif alarm_type == 0x07 then
            alarm_desc = "车辆检测"
        elseif alarm_type == 0x08 then
            alarm_desc = "越界检测"
        elseif alarm_type == 0x09 then
            alarm_desc = "区域入侵"
        else
            alarm_desc = "其他报警"
        end
        
        table.insert(variables, {
            Name = "alarm_type",
            Description = "报警类型",
            Value = alarm_desc
        })
        
        table.insert(variables, {
            Name = "channel",
            Description = "通道号",
            Value = channel
        })
        
        table.insert(variables, {
            Name = "alarm_time",
            Description = "报警时间",
            Value = alarm_time
        })
        
        table.insert(variables, {
            Name = "has_snapshot",
            Description = "是否有截图",
            Value = has_snapshot == 0x01 and "是" or "否"
        })
        
        print(string.format("[IPCamera] 设备%s 报警: 类型=%s, 通道=%d, 时间=%d, 截图=%s",
            deviceAddr, alarm_desc, channel, alarm_time, has_snapshot == 0x01 and "有" or "无"))
        
        return true
        
    elseif cmd == 0x04 then
        -- 云台控制响应
        local result = data[12]
        local direction = data[13]
        local speed = data[14]
        
        table.insert(variables, {
            Name = "ptz_result",
            Description = "云台控制结果",
            Value = result == 0x00 and "成功" or "失败"
        })
        
        table.insert(variables, {
            Name = "ptz_direction",
            Description = "云台方向",
            Value = getPTZDirection(direction)
        })
        
        table.insert(variables, {
            Name = "ptz_speed",
            Description = "云台速度",
            Value = speed
        })
        
        print(string.format("[IPCamera] 设备%s 云台控制响应: 结果=%s, 方向=%s, 速度=%d",
            deviceAddr, result == 0x00 and "成功" or "失败", getPTZDirection(direction), speed))
        
        return true
        
    elseif cmd == 0x05 then
        -- 视频参数响应
        local channel = data[12]
        local resolution = data[13]
        local framerate = data[14]
        local bitrate = data[15] * 256 + data[16]
        
        local resolution_desc = ""
        if resolution == 0x01 then
            resolution_desc = "1920x1080"
        elseif resolution == 0x02 then
            resolution_desc = "1280x720"
        elseif resolution == 0x03 then
            resolution_desc = "640x480"
        else
            resolution_desc = "未知"
        end
        
        table.insert(variables, {
            Name = "video_channel",
            Description = "视频通道",
            Value = channel
        })
        
        table.insert(variables, {
            Name = "video_resolution",
            Description = "视频分辨率",
            Value = resolution_desc
        })
        
        table.insert(variables, {
            Name = "video_framerate",
            Description = "视频帧率",
            Value = framerate,
            Unit = "fps"
        })
        
        table.insert(variables, {
            Name = "video_bitrate",
            Description = "视频码率",
            Value = bitrate,
            Unit = "Kbps"
        })
        
        print(string.format("[IPCamera] 设备%s 视频参数: 通道=%d, 分辨率=%s, 帧率=%dfps, 码率=%dKbps",
            deviceAddr, channel, resolution_desc, framerate, bitrate))
        
        return true
    end
    
    print(string.format("[IPCamera] 未知命令码: %02X", cmd))
    return false
end

-- ============================================================================
-- 核心函数：主动上报处理
-- ============================================================================

function HandleActiveReport(deviceAddr, data, dataLen)
    local result = {
        Success = false,
        NeedResponse = false,
        Response = {},
        EventType = "data",
        DeviceData = {},
        ShouldReport = true
    }
    
    -- 验证数据包
    local valid, msg = validatePacket(data, dataLen)
    if not valid then
        print(string.format("[IPCamera] HandleActiveReport 数据包验证失败: %s", msg))
        return result
    end
    
    local cmd = data[11]
    
    if cmd == 0x01 then
        -- 设备注册
        result.EventType = "login"
        result.DeviceData.device_serial = extractDeviceSerial(data)
        result.DeviceData.device_model = string.format("%c%c%c%c%c%c%c%c",
            data[12], data[13], data[14], data[15],
            data[16], data[17], data[18], data[19])
        result.DeviceData.firmware_version = string.format("%d.%d.%d", data[20], data[21], data[22])
        result.DeviceData.channel_count = data[23]
        result.DeviceData.device_type = "IPCamera"
        
        -- 生成注册响应
        result.NeedResponse = true
        result.Response = {
            0xFF, 0xFE,     -- 帧头
            0x00, 0x12,     -- 长度（18字节）
            data[5], data[6], data[7], data[8], data[9], data[10],  -- 设备序列号
            0x81,           -- 注册响应
            0x00,           -- 注册成功
            0x00, 0x00, 0x00, 0x00,  -- 服务器时间（Unix时间戳）
            0x00, 0x00      -- CRC16（稍后计算）
        }
        -- 设置服务器时间
        local server_time = os.time()
        result.Response[13] = math.floor(server_time / 16777216) % 256
        result.Response[14] = math.floor(server_time / 65536) % 256
        result.Response[15] = math.floor(server_time / 256) % 256
        result.Response[16] = server_time % 256
        -- 计算CRC
        local crc = calcCRC16(result.Response, 1, 16)
        result.Response[17] = math.floor(crc / 256)
        result.Response[18] = crc % 256
        
        result.ShouldReport = false  -- 注册不上报
        result.Success = true
        
        print(string.format("[IPCamera] 设备注册处理: 序列号=%s, 型号=%s",
            result.DeviceData.device_serial, result.DeviceData.device_model))
        
    elseif cmd == 0x02 then
        -- 心跳
        result.EventType = "heartbeat"
        result.DeviceData.device_status = data[12] == 0x00 and "正常" or "异常"
        result.DeviceData.cpu_usage = data[13]
        result.DeviceData.memory_usage = data[14]
        result.DeviceData.temperature = data[15]
        result.DeviceData.storage_status = data[16] == 0x00 and "正常" or "异常"
        result.DeviceData.heartbeat_time = os.time()
        
        -- 心跳响应
        result.NeedResponse = true
        result.Response = {
            0xFF, 0xFE,     -- 帧头
            0x00, 0x0D,     -- 长度（13字节）
            data[5], data[6], data[7], data[8], data[9], data[10],  -- 设备序列号
            0x82,           -- 心跳响应
            0x00,           -- 在线
            0x00, 0x00      -- CRC16（稍后计算）
        }
        local crc = calcCRC16(result.Response, 1, 11)
        result.Response[12] = math.floor(crc / 256)
        result.Response[13] = crc % 256
        
        result.ShouldReport = false  -- 心跳不上报
        result.Success = true
        
        print(string.format("[IPCamera] 心跳处理: CPU=%d%%, 内存=%d%%, 温度=%d℃",
            result.DeviceData.cpu_usage, result.DeviceData.memory_usage, result.DeviceData.temperature))
        
    elseif cmd == 0x03 then
        -- 报警推送
        result.EventType = "alarm"
        
        local alarm_type = data[12]
        if alarm_type == 0x01 then
            result.DeviceData.alarm = "移动侦测"
        elseif alarm_type == 0x02 then
            result.DeviceData.alarm = "遮挡报警"
        elseif alarm_type == 0x06 then
            result.DeviceData.alarm = "人形检测"
        elseif alarm_type == 0x07 then
            result.DeviceData.alarm = "车辆检测"
        else
            result.DeviceData.alarm = "其他报警"
        end
        
        result.DeviceData.alarm_type = alarm_type
        result.DeviceData.channel = data[13]
        result.DeviceData.alarm_time = data[14] * 16777216 + data[15] * 65536 + data[16] * 256 + data[17]
        result.DeviceData.has_snapshot = data[18] == 0x01
        
        -- 报警确认响应
        result.NeedResponse = true
        result.Response = {
            0xFF, 0xFE,     -- 帧头
            0x00, 0x0D,     -- 长度（13字节）
            data[5], data[6], data[7], data[8], data[9], data[10],  -- 设备序列号
            0x83,           -- 报警确认
            0x00,           -- 已收到
            0x00, 0x00      -- CRC16（稍后计算）
        }
        local crc = calcCRC16(result.Response, 1, 11)
        result.Response[12] = math.floor(crc / 256)
        result.Response[13] = crc % 256
        
        result.ShouldReport = true  -- 报警需要上报
        result.Success = true
        
        print(string.format("[IPCamera] 报警处理: 类型=%s, 通道=%d",
            result.DeviceData.alarm, result.DeviceData.channel))
    end
    
    return result
end

-- ============================================================================
-- 核心函数：命令生成
-- ============================================================================

function DeviceCustomCmd(deviceAddr, cmdName, param, value)
    local cmd = {}
    local success = false
    
    -- 解析设备序列号（MAC地址格式：AA:BB:CC:DD:EE:FF）
    local serial_bytes = {}
    if string.find(deviceAddr, ":") then
        for byte_str in string.gmatch(deviceAddr, "[^:]+") do
            table.insert(serial_bytes, tonumber(byte_str, 16))
        end
    else
        serial_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}
    end
    
    if cmdName == "ptz_up" then
        -- 云台向上
        local speed = tonumber(value) or 50  -- 默认速度50
        cmd = {
            0xFF, 0xFE,     -- 帧头
            0x00, 0x0E,     -- 长度（14字节）
            serial_bytes[1], serial_bytes[2], serial_bytes[3],
            serial_bytes[4], serial_bytes[5], serial_bytes[6],
            0x04,           -- 云台控制命令
            0x01,           -- 方向：上
            speed,          -- 速度
            0x00, 0x00      -- CRC16
        }
        local crc = calcCRC16(cmd, 1, 12)
        cmd[13] = math.floor(crc / 256)
        cmd[14] = crc % 256
        success = true
        
    elseif cmdName == "ptz_down" then
        local speed = tonumber(value) or 50
        cmd = {0xFF, 0xFE, 0x00, 0x0E,
               serial_bytes[1], serial_bytes[2], serial_bytes[3],
               serial_bytes[4], serial_bytes[5], serial_bytes[6],
               0x04, 0x02, speed, 0x00, 0x00}
        local crc = calcCRC16(cmd, 1, 12)
        cmd[13] = math.floor(crc / 256)
        cmd[14] = crc % 256
        success = true
        
    elseif cmdName == "ptz_left" then
        local speed = tonumber(value) or 50
        cmd = {0xFF, 0xFE, 0x00, 0x0E,
               serial_bytes[1], serial_bytes[2], serial_bytes[3],
               serial_bytes[4], serial_bytes[5], serial_bytes[6],
               0x04, 0x03, speed, 0x00, 0x00}
        local crc = calcCRC16(cmd, 1, 12)
        cmd[13] = math.floor(crc / 256)
        cmd[14] = crc % 256
        success = true
        
    elseif cmdName == "ptz_right" then
        local speed = tonumber(value) or 50
        cmd = {0xFF, 0xFE, 0x00, 0x0E,
               serial_bytes[1], serial_bytes[2], serial_bytes[3],
               serial_bytes[4], serial_bytes[5], serial_bytes[6],
               0x04, 0x04, speed, 0x00, 0x00}
        local crc = calcCRC16(cmd, 1, 12)
        cmd[13] = math.floor(crc / 256)
        cmd[14] = crc % 256
        success = true
        
    elseif cmdName == "ptz_stop" then
        cmd = {0xFF, 0xFE, 0x00, 0x0E,
               serial_bytes[1], serial_bytes[2], serial_bytes[3],
               serial_bytes[4], serial_bytes[5], serial_bytes[6],
               0x04, 0x00, 0x00, 0x00, 0x00}
        local crc = calcCRC16(cmd, 1, 12)
        cmd[13] = math.floor(crc / 256)
        cmd[14] = crc % 256
        success = true
        
    elseif cmdName == "query_video_params" then
        -- 查询视频参数
        local channel = tonumber(param) or 1
        cmd = {0xFF, 0xFE, 0x00, 0x0E,
               serial_bytes[1], serial_bytes[2], serial_bytes[3],
               serial_bytes[4], serial_bytes[5], serial_bytes[6],
               0x05, channel, 0x00, 0x00, 0x00}
        local crc = calcCRC16(cmd, 1, 12)
        cmd[13] = math.floor(crc / 256)
        cmd[14] = crc % 256
        success = true
        
    elseif cmdName == "snapshot" then
        -- 抓拍
        local channel = tonumber(param) or 1
        cmd = {0xFF, 0xFE, 0x00, 0x0E,
               serial_bytes[1], serial_bytes[2], serial_bytes[3],
               serial_bytes[4], serial_bytes[5], serial_bytes[6],
               0x06, channel, 0x00, 0x00, 0x00}
        local crc = calcCRC16(cmd, 1, 12)
        cmd[13] = math.floor(crc / 256)
        cmd[14] = crc % 256
        success = true
    end
    
    if success then
        print(string.format("[IPCamera] 生成命令: %s, 设备=%s", cmdName, deviceAddr))
    end
    
    return cmd, success, ""
end

-- ============================================================================
-- 打印协议信息
-- ============================================================================
print("[IPCamera] Lua 插件已加载: " .. protocol_name)

